﻿#region 命名空间

using System;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Linq;
using System.Linq.Expressions;
using Sharp.Domain.Model;

#endregion

namespace Sharp.Domain
{
    /// <summary>
    ///     Helper extensions for add IDbSet methods defined only
    ///     for DbSet and ObjectQuery
    /// </summary>
    public static class IQueryableExtensions
    {
        /// <summary>
        /// 过滤已经被逻辑删除的数据
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public static IQueryable<TAggregateRoot> Filter<TAggregateRoot>(this DbSet<TAggregateRoot> query)
            where TAggregateRoot : class
        {
            if (typeof(TAggregateRoot).GetInterface("IStandardState") != null)
            {
                var left = Expression.Parameter(typeof(TAggregateRoot), "m");

                Expression expression = Expression.Constant(true);
                Expression right = Expression.Equal(Expression.Property(left, "EntityState"),
                    Expression.Constant(EntityStateOperate.Normal));

                expression = Expression.And(right, expression);

                var filter = Expression.Lambda<Func<TAggregateRoot, bool>>(expression, left);

                return query.AsQueryable().Where(filter);
            }
            return query.AsQueryable();
        }
        /// <summary>
        ///     OfType extension method for IQueryable
        /// </summary>
        /// <typeparam name="TEntity">The type to filter the elements of the sequence on. </typeparam>
        /// <typeparam name="KEntity"></typeparam>
        /// <param name="queryable">The queryable object</param>
        /// <returns>
        ///     A new IQueryable hat contains elements from
        ///     the input sequence of type TResult
        /// </returns>
        public static IQueryable<KEntity> OfType<TEntity, KEntity>(this IQueryable<TEntity> queryable)
            where TEntity : class
            where KEntity : class, TEntity
        {
            if (queryable is ObjectQuery<TEntity>) //delegate execution in DbSet
                return ((ObjectQuery<TEntity>) queryable).OfType<KEntity>();
            else // probably a IDbSet mock
                return queryable.OfType<KEntity>();
        }
    }
}